﻿using LowCoding.Common;
using LowCoding.Common.Security;
using LowCoding.Domain.Entity;
using LowCoding.Dto;
using LowCoding.Dto.Sys;
using Mapster;
using SqlSugar;
using System.Collections.Generic;

namespace LowCoding.Application.Sys.User
{
    /// <summary>
    /// 用户模块
    /// </summary>
    public class SysUserService : ServiceBase<SysUser, SysUserInput, SysUserOutput, SysUserSearchInput, string>, ISysUserService//继承自定义的泛型服务接口和用户模块的接口
    {
        /// <summary>
        /// 校验用户账号密码
        /// </summary>
        /// <param name="loginModel"></param>
        /// <returns></returns>
        //同步和异步主要用于修饰方法。当一个方法被调用时，
        //调用者需要等待该方法执行完毕并返回才能继续执行;
        //当一个方法被调用时立即返回，并获取一个线程执行该方法内部的业务，
        //调用者不用等待该方法执行完毕，我们称这个方法为异步方法。
        //Task：任务，线程池线程,使用的本地队列，使线程之间的资源竞争减少
        public async Task<SysUserOutput> CheckUserLoginWithMd5Pwd(LoginInput loginModel)
        {
            //通过传过来的参数用户Code和数据库中的用户Code 作比较
            //如果相同的话查询这条用户信息进行显示
            var user = await _client.Queryable<SysUser>()
                   .Where((us) => us.UsrCode == loginModel.Code && us.UsrPassword.Equals(loginModel.Password))
                   //根据用户名查询用户信息 
                   .Select((us) => us).SingleAsync();
            //string.Compare:比较两个指定的 String 对象，并返回一个指示二者在排序顺序中的相对位置的整数。
            //Comparr 就是比较两段的代码,大小写问题
            //然后开始进行判断如果上面查询出来的数据不为空并且传过来的密码参数和查询数据库中的参数一致(大小写也一致)
            if (user != null && string.Compare(user.UsrPassword, loginModel.Password, true) == 0)
            {
                //SysUserOutput sysUser = new SysUserOutput();
                var list = user.Adapt<SysUserOutput>();
                list.UserId = user.Id;
                return list;
            }
            return null;
        }

        /// <summary>
        /// 用户新增对密码进行md5加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<SysUserOutput> UserInsert(SysUserInput input)
        {
            _client.Ado.BeginTran();//开始事务 成功就全部成功 如果有一条不成功,就Rollback 回滚，保证数据的唯一性，保证数据不会出错
            try
            {
                //密码MD5加密
                //获取默认密码并且调用MD5加密给传过来的参数input中的密码赋值
                //APPSetting是一个封装类,调用这个封装类中的获取默认密码的方法
                input.UsrPassword = MD5Encrypt.GetMD5(AppSettings.defaultpass);
                //获取用户表的主键赋值给Keyarray
                string[] keyarray = GetPrimaryKeys(typeof(SysUser));
                //通过传过来的参数 和 获取的用户主键 获取实体
                var model = GetEntity(input, keyarray);
                //新增人员，修改人员
                model.Creator = "孙悟空";
                model.Lastmodifier = "猪八戒";
                //使用awit SqlSugar的插入方法进行新增操作 新增完之后赋值给result变量
                var result = await _client.Insertable(model).ExecuteReturnEntityAsync();
                //AppManager 是一个封装获取Token的类
                //这里把获取的Token信息赋值给定义的cacheuser变量
                var cacheuser = AppManager.GetCurrentUser();
                //如果传过来的参数信息input中的角色不为空的话
                if (!input.UsrRole.IsNullOrEmpty())
                {
                    //就把这个角色分割成数组的形式
                    string[] roleids = input.UsrRole.Split(',');
                    //根据条件角色Id = 分割角色的Id 用户Id = result中的Id,Id = 雪花Id
                    //条件查询 并赋值给实例化的用户角色表 
                    List<SysUserrole> userrole = roleids.Select(it => new SysUserrole()
                    { RleId = it, UerId = result.Id, Id = Ids.NextIdString() }).ToList();
                    //判断查出来的用户角色表 是否有数据
                    if (userrole.Count > 0)
                    {
                        //添加用户角色，进行异步添加操作
                        await _client.Insertable(userrole).ExecuteCommandAsync();
                    }
                }
                _client.Ado.CommitTran();//提交事务
                return model.Adapt<SysUserOutput>();//映射dto进行显示
            }
            catch (Exception ex)//捕捉异常，回滚事务
            {
                //如果有一条数据添加失败 就回滚
                _client.Ado.RollbackTran();
                ex.ToErrorLog();
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 修改用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ResponseMessageModel> UpdateUserAsync(SysUserInputUpt_Dto input)
        {
            //Mapster:数据转化
            //首先用Mapster 转化实体用户表
            var Entity = input.Adapt<SysUser>();
            //调用SqlSugar 中的updateTable的方法 出来的结果赋值给result变量
            int result = _client.Updateable(Entity).ExecuteCommand();
            //判断是否有数据
            if (result > 0)
            {
                //返回统一返回值 成功
                return new ResponseMessageModel
                {
                    success = true,
                    code = ResponseCodeEnum.Success,
                    data = result.ToString(),
                    message = "修改成功！"
                };
            }
            else
            {
                //返回统一返回值 失败
                return new ResponseMessageModel
                {
                    success = false,
                    code = ResponseCodeEnum.Fail,
                    data = result.ToString(),
                    message = "修改失败！"
                };
            }
        }

        /// <summary>
        /// 重置密码(并未使用)
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultpass"></param>
        /// <returns></returns>
        public async Task<bool> UserResetPass(string key, string defaultpass)
        {
            //根据传过来的参数进行语句查询和赋值
            //Key = 主键Id 就调用SqlSugar中的修改某列方法 给密码重新赋值MD5加密后的默认密码
            await UpdateColumnsAsync(new SysUserInput()
            { Id = key, UsrPassword = MD5Encrypt.GetMD5(defaultpass ?? "123456").ToUpper() },
            x => new { x.UsrPassword, x.Lastmodified, x.Lastmodifier });
            return true;
        }

        /// <summary>
        /// 用户批删(物理)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<UpdateResult> DelUserAsync(List<string> id)
        {
            _client.Ado.BeginTran(); //使用事务 成功则都成功 只要有一处不成功就RollBack 回滚回开始的时候 保持数据的一致性
            try
            {
                //根据传过来的参数Id 查询用户表 查出用户信息 进行删除
                await _client.Deleteable<SysUser>().Where(it => id.Contains(it.Id)).ExecuteCommandAsync();
                //批删用到的是Contains 包含的语法 查询用户角色表的关联表一般要用Contains包含来批删
                //根据条件查询用户Id 获取用户信息 然后 删除用户角色关联信息
                await _client.Deleteable<SysUserrole>().Where(it => id.Contains(it.UerId)).ExecuteCommandAsync();
                //CmmitTran 事务提交
                _client.Ado.CommitTran();
                //return 返回修改结果 ture 修改成功
                return new UpdateResult { result = true };
            }
            catch (Exception e)
            {
                //RollbackTran 回滚事务 发生错误就直接走这一步
                _client.Ado.RollbackTran();
                //return 返回修改结果 false 修改失败
                return new UpdateResult { result = false, message = e.Message };
            }
        }
        /// <summary>
        /// 简易显示
        /// </summary>
        /// <returns></returns>
        public async Task<ResponseMessageModel> Getlist()
        {
            //统一返回值
            return new ResponseMessageModel
            {
                code = ResponseCodeEnum.Success,
                // 调用SqlSugar显示方法
                data = _client.Queryable<SysUser>().ToList(),
                message = "成功",
                success = true,
            };
        }

        /// <summary>
        /// 用户单删(物理)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ResponseMessageModel> DeleteUserById(string id)
        {
            //根据传过来的参数Id 查询出用户信息 再调用SqlSugar中的删除方法进行删除操作1
            _client.Deleteable<SysUser>().Where(new SysUser { Id = id }).ExecuteCommand();
            //统一返回值
            return new ResponseMessageModel
            {
                success = true,
                code = ResponseCodeEnum.Success,
                message = "删除成功！"
            };
        }

        public List<SysName> sysNames() 
        {
            return _client.Queryable<SysName>().ToList();
        }

    }
}
